// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Collections.Specialized;
using System.Web;
using System.Net;
using System.Globalization;
using System.Xml;

using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Proxy;

namespace Microsoft.TeamFoundation.Migration.Toolkit.Wit
{
    /// <summary>
    /// TFS file attachment.
    /// </summary>
    class TfsMigrationFileAttachment: IMigrationFileAttachment
    {
        private Attachment m_attachment;        // WIT OM object representing a file attachment
        private Nullable<int> m_fileId;         // ID of the file attachment
        private string m_tempDir;               // Temp directory

        /// <summary>
        /// Consturctor.  Initializes file attachment.
        /// </summary>
        /// <param name="attach">Attachment information from WIT OM.</param>
        /// <param name="fileAttachConfig">File attachment configuration settings.</param>
        internal TfsMigrationFileAttachment(
            Attachment attach, 
            string tempDir)
        {
            m_attachment = attach;
            m_fileId = null;
            m_tempDir = tempDir;
        }

        /// <summary>
        /// Returns the file ID.
        /// </summary>
        public int FileID { get { return GetFileID(m_attachment.Uri.Query); } }

        
        #region IMigrationFileAttachment Members
        /// <summary>
        /// Returns the name of the file.
        /// </summary>
        public string Name { get { return m_attachment.Name; } }

        /// <summary>
        /// Returns the file size.
        /// </summary>
        public long Length { get { return m_attachment.Length; } }

        /// <summary>
        /// Returns the date/time the file was created.
        /// </summary>
        public DateTime UtcCreationDate { get { return m_attachment.CreationTimeUtc; } }

        /// <summary>
        /// Returns the date/time the file was last updated.
        /// </summary>
        public DateTime UtcLastWriteDate { get { return m_attachment.LastWriteTimeUtc; } }

        /// <summary>
        /// Returns any comment about the file.
        /// </summary>
        public string Comment { get { return m_attachment.Comment; } }

        /// <summary>
        /// Gets the contents of the file when needed for comparison.
        /// </summary>
        /// <returns>Contents of the file.</returns>
        public Stream GetFileContents()
        {
            string tempFile = Path.Combine(m_tempDir, Guid.NewGuid().ToString());

            // Download attachment into the given file
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(m_attachment.Uri);
            request.Method = "GET";
            request.Credentials = CredentialCache.DefaultNetworkCredentials;

            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    throw new WitMigrationException(string.Format(CultureInfo.InvariantCulture, 
                        Resources.BadHttpResponse, response.StatusCode.ToString()));
                }

                // Copy result to localFile stream
                using (Stream responseStream = response.GetResponseStream())
                {
                    byte[] buffer = new byte[1024];
                    int bytesRead;

                    // Create the new file then stream into it
                    FileStream localFile = new FileStream(
                        tempFile, 
                        FileMode.CreateNew, 
                        FileAccess.ReadWrite, 
                        FileShare.None, 
                        buffer.Length, 
                        FileOptions.DeleteOnClose | FileOptions.SequentialScan);
                    try
                    {
                        while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            localFile.Write(buffer, 0, bytesRead);
                        }

                        // Rewind
                        localFile.Seek(0, SeekOrigin.Begin);
                        return localFile;
                    }
                    catch
                    {
                        localFile.Dispose();
                        throw;
                    }
                }
            }
        }

        #endregion


        #region Private Methods
                
        /// <summary>
        /// Get the file ID from the query string.
        /// </summary>
        /// <param name="qstring">Query string from the attachment Uri.</param>
        /// <returns>File ID.</returns>
        private int GetFileID(string qstring)
        {
            if (m_fileId == null)
            {
                NameValueCollection qargs = HttpUtility.ParseQueryString(qstring);
                string fileIdStr = qargs.Get("FileID");
                if (string.IsNullOrEmpty(fileIdStr) == false)
                {
                    try
                    {
                        m_fileId = int.Parse(fileIdStr, CultureInfo.InvariantCulture);
                    }
                    catch (Exception ex)
                    {
                        throw new ArgumentException(Resources.FileIdNotInteger, ex);
                    }
                }
                if (m_fileId <= 0)
                {
                    m_fileId = null;
                    throw new ArgumentException(Resources.FileIdNotFound);
                }
            }
            return (int)m_fileId;
        }

        #endregion
    }
}
